package config

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/spf13/viper"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

var configFile = flag.String("c", "config/conf.json", "the Config file path")

type CollectConf struct {
	LogPath string `json:"logPath"`
	Topic   string `json:"topic"`
}

type Config struct {
	Host     string //连接地址
	Username string //连接用户名
	Password string //连接密码
	Token    string //连接的token
	Drive    string //中间件 etcd/consul/zk
	Type     string //配置数据格式 json\yaml...
	Path     string //配置存储目录
}

//type CallFunc func(v *viper.Viper)

var CallBack func(v *viper.Viper)

type IConfigService interface {
	Init() *viper.Viper
	GetViper(v *viper.Viper) error
	Get() ([]byte, error)
	Watch(v *viper.Viper)
	Set(value string) error
	SetPath(key string)
}

func GetConfig(srv string) *viper.Viper {
	flag.Parse()
	conf := &Config{}
	if *configFile == "" {
		tp := os.Getenv("CONFIG_TYPE")
		if tp == "" {
			panic("环境变量CONFIG_TYPE未配置")
		}

		addr := os.Getenv("CONFIG_ADDR")
		if addr == "" {
			panic("环境变量CONFIG_ADDR未配置")
		}

		if tp != "etcd" && tp != "zk" && tp != "consul" {
			token := os.Getenv("CONFIG_TOKEN")
			if token == "" {
				panic("环境变量CONFIG_TOKEN未配置")
			}
			// 从配置中心获取
			url := fmt.Sprintf("%v/configure/config?service=%v&token=%v", addr, srv, token)
			client := http.Client{Timeout: 10 * time.Second}
			response, err := client.Get(url)
			if err != nil {
				panic("请求配置中心信息异常" + err.Error())
			}
			defer response.Body.Close()

			respData := struct {
				Code int64   `json:"code"`
				Msg  string  `json:"msg"`
				Data *Config `json:"data"`
			}{}

			b, _ := io.ReadAll(response.Body)
			if json.Unmarshal(b, &respData) != nil {
				panic("解析配置中心失败")
			}
			if respData.Code != 200 || respData.Data == nil {
				panic("获取配置连接信息失败:" + respData.Msg)
			}
			conf = respData.Data
		} else {
			path := os.Getenv("CONFIG_PATH")
			if path == "" {
				panic("配置路径CONFIG_PATH未配置")
			}
			conf = &Config{
				Drive: tp,
				Host:  addr,
				Type:  "json",
				Path:  path,
			}
		}
	} else {
		temp := strings.Split(*configFile, ".")
		conf = &Config{
			Drive: "local",
			Type:  temp[len(temp)-1],
			Path:  *configFile,
		}
	}
	return Init(conf)
}

func Init(conf *Config) *viper.Viper {
	var configService IConfigService
	var err error
	switch conf.Drive {
	case "etcd":
		configService, err = NewEtcd(conf)
	case "zk":
		configService, err = NewZK(conf)
	case "consul":
		configService, err = NewConsul(conf)
	case "local":
		configService, err = NewLocal(conf)
	default:
		panic("config type is fail")
	}
	if err != nil {
		panic("config drive fail:" + err.Error())
	}
	return configService.Init()
}
